/****************************************************************************\
*
* hpidd.c
*
* This module determines the HP laptop product IDs.
*
* 00/06/30 lnc - V1.12, updated for Jaws.
* 00/02/17 bw - V1.11, updated for Oddjob 2, Sterling.
* 98/06/09 lnc - V1.10, updated for Galileo 2, Voyager 2, Oddjob.
* 98/06/05 lnc - V1.09, updated for Apollo 2.
* 98/06/02 lnc - V1.08, removed GetDMIdata() and SMI function
* method from iGet_Prod_ID(); reorganized routine order.
* 98/05/20 lnc - V1.07, modified HP_ID_Table[] and vCheck_HP_ID()
* to distinguish Tillamook from Deschutes and OB3100
* from OB2100 for use of DMI tables; vCheck_HP_ID() now
* gets BIOS ID and model name to use with added
* routine vTune_HP_ID().
* 98/05/01 lnc - V1.06, renamed GetProdID to iGet_Prod_ID().
* 98/03/01 lnc - V1.05, added modifications to GetProdID() to
* directly access DMI structures from the SMBIOS
* structure table; modified renamed HP_ID_Table to
* set appropriate index for product ID returned from
* GetProdID() through direct access to DMI structures,
* SMBIOS function access to DMI structures, or
* INT 15h, function 4DD4h.
* 98/02/18 lnc - V1.04, modified key IDs of HpIDTable, and
* iDo_Int15() for new version of INT 15 - qCX.MY.ZZ,
* BIOS version 37a.
* 98/02/11 lnc - V1.03, modified key IDs of HpIDTable, and
* iDo_Int15() for new version of INT 15 - q.CX.MY.ZZ,
* BIOS version 35a.
* 98/01/19 lnc - V1.02, modified key IDs of HpIDTable, debug for
* iDo_Int15().
* 97/12/10 lnc - V1.01, modified for Medium model, added new
* catagory to LookUp structure for a this test program.
* 97/12/08 bw - V1.00, created.
*
\****************************************************************************/
#include <stdio.h>
#include <string.h>
#include "model.h"
#define MAXBUFSIZE 8192
#define BID_BA 0x4241
#define BID_CB 0x4342
#define BID_CC 0x4343
#define BID_CD 0x4344
#define BID_CE 0x4345
#define BID_CF 0x4346
#define BID_CG 0x4347
#define BID_CH 0x4348
#define BID_CI 0x4349
#define BID_CJ 0x434A
#define BID_CK 0x434B
#define BID_CL 0x434C
#define BID_C0 0x4330
#define BID_EA 0x4541
#define BID_FA 0x4641
typedef struct
{
unsigned inSig;
int key;
} LookUp;
typedef unsigned char BYTE;
typedef unsigned short WORD;
int iGet_Prod_ID (void);
static BYTE far *bfpFind_Dmi_Table(void);
static int iGetPlatformId(char far *cpPtr);
static void vCheck_HP_ID(BYTE far *fpntr);
static char far *cfpGet_String(int n, BYTE far *fpntr);
static void vTune_HP_ID(void);
static BYTE far *bfpGet_Next_Structure(BYTE far *s);
static unsigned uDo_Int15 (void);
static LookUp HP_ID_Table[] =
{
{0x0301, OB4000}, // 1 Pegasus
{0x0401, OB5000}, // 2 Tristar
{0x0402, OB5500}, // 3 Quadstar
{0x0403, OB5700}, // 4 AA, Polaris
{0x0404, OB2000}, // 5 AA, Reno
{0x0501, OB800O}, // 6 Orion
{0x0502, OB800M}, // 7 AB, Mercury, MMX
{0x0601, OB3000}, // 8 CA, Magellan
{BID_BA, OBSOJOURN}, // 9 BA, Sputnik
{BID_CB, OB7100T}, // 10 CB, Galileo 1, Tillamook
{BID_CC, OB7100D}, // 11 CC, Galileo 1, Deschutes
{BID_CH, OB7150}, // 12 CH, Galileo 2, Deschutes, 300 Mhz
{BID_CD, OB4100T}, // 13 CD, Voyager 1, Tillamook
{BID_CE, OB4100D}, // 14 CE, Voyager 1, Deschutes
{BID_CI, OB4150A}, // 15 CI, Voyager 2, Deschutes, 300 Mhz
{BID_CF, OB3100}, // 16 CF, Apollo 1, Tillamook, 266 Mhz
{BID_C0, OB2100T}, // 17 CF, Apollo 1, Tillamook, 233 Mhz
{BID_CG, OB2100D}, // 18 CG, Apollo 2, Deschutes, 266 Mhz
{BID_CJ, OB900A}, // 19 CJ, Oddjob, Deschutes, 266 Mhz
{BID_CK, OB4150B}, // 20 CK, Voyager 3.9, 4, 4.2
{BID_CL, OB900B}, // 21 CL, Oddjob 2, 2.5, 2.7
{BID_EA, OB6000}, // 22 EA, Sterling
{BID_FA, OB500}, // 23 FA, Jaws
{0, 0} // Marks end of table
};
static char HP_Str[] = "HP OmniBook PC";
#define HP_STR_BSZ (sizeof HP_Str) - 3
static char Model_Bf[16] = "";
static unsigned uBIOS_Sig = 0;
static unsigned uProdID = 0;
static unsigned uOmniBook = 0;
/****************************************************************************\
* iGet_Prod_ID
*
* Identify the computer, first trying the DMI tables and if that
* fails then trying INT 15 function 4DD4.
*
* Output:
* return - -1, unknown
* -2, Vectra
* OB4000, OB 4000
* OB5000, OB 5000
* OB5500, Quadstar
* OB5700, Polaris
* OB2000, Reno
* OB800O, Orion0
* OB800M, Mercury, MMX
* OB3000, Magellan
* OBSOJOURN, Sputnik
* OB7100T, Galileo 1, Tillamook
* OB7100D, Galileo 1, Deschutes
* OB7150, Galileo 2, Deschutes, 300 Mhz
* OB4100T, Voyager 1, Tillamook
* OB4100D, Voyager 1, Deschutes
* OB4150A, Voyager 2, Deschutes, 300 Mhz
* OB4150B, Voyager 3.9, 4, 4.2
* OB3100, Apollo 1, 266 Mhz
* OB2100T, Apollo 1, 233 Mhz
* OB2100D, Apollo 2, Deschutes, 266 Mhz
* OB900A, Oddjob, Deschutes, 266 Mhz
* OB900B, Oddjob 2
* OB6000 Sterling
* OB500 Jaws.
\****************************************************************************/
int
iGet_Prod_ID(void)
{
BYTE far *fpntr;
unsigned int i;
uBIOS_Sig = 0;
uProdID = 0;
uOmniBook = 0;
// first try accessing DMI tables directly
if ((fpntr = bfpFind_Dmi_Table()) != NULL)
{
do
{
vCheck_HP_ID(fpntr);
if (uOmniBook && uBIOS_Sig)
{
vTune_HP_ID(); // tune for crummy DMI design
for (i = 0; HP_ID_Table[i].inSig != 0; i++)
if (HP_ID_Table[i].inSig == uBIOS_Sig)
return HP_ID_Table[i].key; // OK
break; // bad product ID, NOT found in table
}
}
while ((fpntr = bfpGet_Next_Structure(fpntr)) != 0);
}
// DMI did not work, use INT 15h , function 4DD4h
if ((uProdID = uDo_Int15()) < 0)
return (int) uBIOS_Sig; // NOT HP OmniBook
for (i = 0; HP_ID_Table[i].inSig != 0; i++)
if (HP_ID_Table[i].inSig == uBIOS_Sig)
return HP_ID_Table[i].key; // OK return
return -1; // NOT found in table
}
/****************************************************************************\
* bfpFind_Dmi_Table
*
* This function searches BIOS segment F000h for the signature "_DMI_"
* and returns a pointer to the SMBIOS structure table.
*
* Output:
* return - NULL, "_DMI_" signature notfound
* pointer to SMBIOS structure table.
\****************************************************************************/
static BYTE far *
bfpFind_Dmi_Table(void)
{
BYTE far *pDmiTable;
_asm {
push es
push bx
push cx
mov ax, 0xf000 ; start at beginning of F000h segment
mov es, ax
xor bx, bx
Loop1:
; look for "_DMI_" signature
cmp WORD PTR es:[bx], 'D_' ; "_D"
jne NotYet
cmp WORD PTR es:[bx + 2], 'IM' ; "MI"
jne NotYet
cmp BYTE PTR es:[bx + 4], '_' ; "_"
je FoundDmi
NotYet:
add bx, 0x10 ; next paragraph still in segment
jnc Loop1 ; yes
xor bx, bx ; no, signature not found,
xor cx, cx ; return NULL pointer
jmp Done
FoundDmi:
; found it, get 32-bit real mode physical starting address of
;read-only SMBIOS structure table
mov cx, WORD PTR es:[bx + 9] ; get segment
shl cx, 1
shl cx, 1
shl cx, 1
shl cx, 1
mov bx, WORD PTR es:[bx + 8] ; get offset
and bx, 0xff
Done:
mov WORD PTR pDmiTable, bx ; save offset
mov WORD PTR pDmiTable[2], cx ; save segment
pop cx
pop bx
pop es
}
return pDmiTable;
}
/****************************************************************************\
* iGetPlatformId
*
* Input:
* cpPtr - pointer to a structure in the SMBIOS
* structure table.
*
* Output:
* return - -1, not an Omnibook
* xy, 2-character platform ID (iOmniBook == 1).
\****************************************************************************/
static int
iGetPlatformId(char far *cpPtr)
{
int iRtn;
while (*(cpPtr++) != '.')
;
if (*cpPtr == 'M')
{
uOmniBook = 1;
iRtn = ((int) *(cpPtr - 3) << 8);
iRtn |= (int) *(cpPtr - 2);
return iRtn;
}
return -1;
}
/****************************************************************************\
* vCheck_HP_ID
*
* This routine checks the SMBIOS structure table for structures of
* type 1h and 80h for Product Name and Notebook ID, respectively.
*
* Input:
* fpntr - pointer to a structure in the SMBIOS
* structure table.
*
* Output:
* sets uBIOS_Sig to BIOS ID if structure type 0h is found,
* sets uOmniBook to 1 if structure type 1h is found,
* sets uProdID to product ID if structure 80h is found:
* 7, Galileo
* 8, Voyager
* 9, Apollo.
\****************************************************************************/
static void
vCheck_HP_ID(BYTE far *fpntr)
{
char far *fstr;
int iTmp;
switch (*fpntr)
{
case 0x00:
// Type 0h: BIOS Information
// get BIOS version
iTmp = iGetPlatformId(cfpGet_String(0x5, fpntr));
if (iTmp != -1)
uBIOS_Sig = (unsigned) iTmp;
else
uBIOS_Sig = 0;
return;
case 0x01:
// Type 1h: System Information
// check product name
if (_fstrcmp(cfpGet_String(0x5, fpntr), HP_Str) == 0)
uOmniBook = 1; // Product Name checks out
// get model name
if (_fstrncmp((fstr = cfpGet_String(0x6, fpntr)),
HP_Str, HP_STR_BSZ) == 0)
_fstrcpy(Model_Bf, fstr + HP_STR_BSZ);
return;
case 0x80:
// Type 80h: HP ID
// get notebook ID
uProdID = *(fpntr + 6);
return;
}
}
/****************************************************************************\
* cfpGet_String
*
* This routine finds a string in the string area of an SMBIOS structure.
*
* Input:
* n - offset of string type, determining string
* number
* fpntr - pointer to a structure in the SMBIOS
* structure table.
*
* Output:
* returns - NULL, length byte is zero
* pointer to a string in a structure of
* finite length; string may be a NULL string.
\****************************************************************************/
static char far *
cfpGet_String(int n, BYTE far *fpntr)
{
unsigned i, j;
BYTE far *p;
if ((j = *(fpntr + 1)) == 0)
return NULL; // length of formatted area is zero
p = fpntr + j; // point to start of string section
j = *(fpntr + n); // get string number
for (i = 1; i < j; i++)
while (*p++)
; // move to start of appropriate string
return (char far *) p;
}
/****************************************************************************\
* vTune_HP_ID
*
* This routine splits the 'CF' from the OB2100 & 3100 into 2 IDs
*
\****************************************************************************/
static void
vTune_HP_ID(void)
{
switch (uBIOS_Sig)
{
case BID_CF:
uBIOS_Sig = (Model_Bf[0] == '2') ? BID_C0 : BID_CF;
return;
}
}
/****************************************************************************\
* bfpGet_Next_Structure
*
* This routine searches to the end of a structure for the start of
* the next structure in the SMBIOS structure table.
*
* Input:
* s - pointer to a structure in the SMBIOS
* structure table.
*
* Output:
* returns - NULL, length byte is zero
* pointer to next structure.
\****************************************************************************/
static BYTE far *
bfpGet_Next_Structure(BYTE far *s)
{
unsigned len;
// get length of formatted area
if ((len = *(s + 1)) == 0)
return NULL; // length of formatted area is zero
// point to string area and move past end
for (s += len; *s != '\0' || *(s + 1) != '\0'; s++)
;
s += 2; // point at next structure
return s;
}
/****************************************************************************\
* uDo_Int15
*
* Do INT 15 function 4DD4h.
*
* Output:
* return - -1, Not HP OmniBook, int 15 funct 4DD4
* not supported
* -2, Vectra (int 15 funct 4DD4 returned
* HP div ID != MCD)
* nn, For old OB, nn = chip set + model;
* for newer OB, nn = 2 letter platform
* identifier.
*
* Note - OB800, OB3000 and probably older versions of the Omnibook
* use the old version of INT 15h.
\****************************************************************************/
static unsigned
uDo_Int15(void)
{
unsigned axreg;
_asm
{
push es
push di
mov ax, 0x4DD4
int 15h
cmp bx, 'HP' // BX == 0x4850 ?
je OldOB // Yes, old version of INT 15h
cmp bx, 'hp' // BX == 0x6870 ?
jne NotOB // NO, error, not a OmniBook
// ES:DI -> <blank>AA.UX.YY, qAA.UX.YY, cAA.UX.YY, bAA.UX.YY,
// or AA.UX.YY
mov al, es:[di] // YES, check first character for
// ' ', 'q', 'c', or 'b'
cmp al, ' '
je Prfx
cmp al, 'q'
je Prfx
cmp al, 'c'
je Prfx
cmp al, 'b'
jne NoPrfx
Prfx:
inc di
NoPrfx:
mov ax, es:[di] // get AA field
xchg ah, al
cmp byte ptr es:[di + 3], 'M' // U field == M for MCD ?
je Exit // YES, MCD
mov ax, -2 // NO, must be Vectra
jmp Exit
OldOB:
mov ax, cx // CH = chip set, CL = model
jmp Exit // Magellan, Mercury, Orion, etc.
NotOB:
mov ax, -1 // not Hewlett-Packard product
Exit:
pop di
pop es
mov axreg, ax
}
return axreg;
}